package com.aiden.app.common.view.banner

import android.content.Context
import android.graphics.*
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.OrientationHelper
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.RelativeLayout
import com.aiden.app.common.R
import com.aiden.app.common.base.BaseRecyclerViewAdapter
import com.aiden.app.common.extension.dp2px
import com.aiden.app.common.extension.inflate
import com.aiden.app.common.extension.setVisible
import com.aiden.app.common.view.banner.adapter.CTAdapter
import com.aiden.app.common.view.banner.adapter.CTViewHolderCreator
import com.aiden.app.common.view.banner.listener.CTOnPageChangeListener
import com.aiden.app.common.view.banner.listener.OnPageChangeListener
import java.lang.ref.WeakReference

/**
 * 轮播图
 *
 * @author yanggeng
 * @date 2019/1/8 上午11:15
 */
class CTBanner<T> : RelativeLayout {

    private val TAG = CTBanner::class.java.simpleName

    private var canLoop = true
    private var turning = true
    private val canTurn = true
    private var autoTurningTime = 3000L
    private var unselectedColor = Color.WHITE
    private var selectedColor = Color.BLACK
    private var indicatorRadius = 0
    private var indicatorMargin = 0
    private var indicatorMarginBottom = 0
    private var showBottomArc = false
    private var realHeight = 0
    private var realWidth = 0
    private var arcHeight = 20
    private var showIndicator = true

    private lateinit var viewPager: CTViewPager
    private lateinit var pagerAdapter: CTAdapter<T>
    private lateinit var indicator: IndicatorView
    private lateinit var datas: MutableList<T>
    private var onPageChangeListener: OnPageChangeListener? = null
    private lateinit var indicatorPageChangeListener: CTOnPageChangeListener
    private lateinit var loopScrollHelper: CTLoopScrollHelper
    private lateinit var turnTask: CTTurnTask<T>
    private lateinit var holderCreator: CTViewHolderCreator<T>

    constructor(context: Context) : super(context) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {

        val a = context.obtainStyledAttributes(attrs, R.styleable.CTBanner)
        unselectedColor = a.getColor(R.styleable.CTBanner_CT_indicator_unselected, Color.WHITE)
        selectedColor = a.getColor(R.styleable.CTBanner_CT_indicator_selected, Color.BLACK)
        indicatorRadius = a.getDimensionPixelSize(R.styleable.CTBanner_CT_indicator_radius, context.dp2px(2))
        indicatorMargin = a.getDimensionPixelSize(R.styleable.CTBanner_CT_indicator_margin, context.dp2px(5))
        indicatorMarginBottom = a.getDimensionPixelSize(R.styleable.CTBanner_CT_indicator_margin_bottom, context.dp2px(8))
        showBottomArc = a.getBoolean(R.styleable.CTBanner_CT_bottom_arc, false)
        showIndicator = a.getBoolean(R.styleable.CTBanner_CT_show_indicator, true)
        a.recycle()
        init(context)
    }

    private fun init(context: Context) {
        val viewPagerView = context.inflate(R.layout.layout_viewpager, this, true)

        viewPager = viewPagerView.findViewById(R.id.viewpager)
        indicator = viewPagerView.findViewById(R.id.indicator)
        val linearLayoutManager = LinearLayoutManager(context, OrientationHelper.HORIZONTAL, false)
        viewPager.layoutManager = linearLayoutManager
        loopScrollHelper = CTLoopScrollHelper()
        turnTask = CTTurnTask<T>(this)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (changed && showBottomArc) {
            calculateLayout()
        }
    }

    fun setPages(holderCreator: CTViewHolderCreator<T>, datas: MutableList<T>): CTBanner<T> {
        this.datas = datas
        this.holderCreator = holderCreator
        pagerAdapter = CTAdapter(this.holderCreator, datas)
        viewPager.adapter = pagerAdapter

        if (showIndicator) {
            indicator.setSelectedColor(selectedColor)
                    .setUnselectedColor(unselectedColor)
                    .setDotRadius(indicatorRadius.toFloat())
                    .setMarginBottom(indicatorMarginBottom)
                    .setDotCount(datas.size)
                    .changePosition(0)
            indicatorPageChangeListener = CTOnPageChangeListener(indicator)
            if (onPageChangeListener != null) {
                indicatorPageChangeListener.setOnPageChangeListener(onPageChangeListener!!)
            }
            loopScrollHelper.setOnPageChangeListener(indicatorPageChangeListener)
        } else {
            indicator.setVisible(false)
            if (onPageChangeListener != null) {
                loopScrollHelper.setOnPageChangeListener(onPageChangeListener!!)
            }
        }

        loopScrollHelper.firstItemPosition = if (canLoop) datas.size else 0
        loopScrollHelper.attachToRecyclerView(viewPager)

        return this
    }

    fun setLoop(canLoop: Boolean): CTBanner<T> {
        this.canLoop = canLoop
        pagerAdapter.canLoop = canLoop
        notifyDataSetChanged()
        return this
    }

    fun notifyDataSetChanged() {
        pagerAdapter.notifyDataSetChanged()
        loopScrollHelper.setCurrentItem(if (canLoop) datas.size else 0)
        if (showIndicator) {
            indicator.setDotCount(datas.size).changePosition(0)
        }
        requestLayout()
    }

    fun setOnPageChangeListener(onPageChangeListener: OnPageChangeListener): CTBanner<T> {
        this.onPageChangeListener = onPageChangeListener
        if (showIndicator) {
            indicatorPageChangeListener.setOnPageChangeListener(onPageChangeListener)
            loopScrollHelper.setOnPageChangeListener(indicatorPageChangeListener)
        } else {
            loopScrollHelper.setOnPageChangeListener(onPageChangeListener)
        }
        return this
    }

    fun setOnItemClickListener(onItemClickListener: BaseRecyclerViewAdapter.OnItemClickListener): CTBanner<T> {
        pagerAdapter.setOnItemClickListener(onItemClickListener)
        return this
    }

    fun getCurrentItem(): Int {
        return loopScrollHelper.getCurrentItem()
    }

    fun setCurrentItem(position: Int, smoothScroll: Boolean = false): CTBanner<T> {
        loopScrollHelper.setCurrentItem(if (canLoop) datas.size + position else position, smoothScroll)
        return this
    }

    fun setFirstItem(position: Int): CTBanner<T> {
        loopScrollHelper.firstItemPosition = if (canLoop) datas.size + position else position
        return this
    }

    fun startTurning(autoTurnTime: Long): CTBanner<T> {
        if (autoTurnTime < 0) return this

        if (turning) {
            stopTurning()
        }

        this.autoTurningTime = autoTurnTime
        turning = true
        postDelayed(turnTask, autoTurnTime)
        return this
    }

    fun stopTurning() {
        turning = false
        removeCallbacks(turnTask)
    }

    fun setIndicatorVisible(visible: Boolean): CTBanner<T> {
        indicator.visibility = if (visible) View.VISIBLE else View.GONE
        return this
    }

    private lateinit var clipPath: Path

    private fun calculateLayout() {
        realHeight = measuredHeight
        realWidth = measuredWidth
        if (measuredHeight > 0 && measuredWidth > 0) {
            clipPath = createClipPath()
        }
    }

    private fun createClipPath(): Path {
        val path = Path()
        path.moveTo(0f, 0f)
        path.lineTo(0f, height.toFloat())
        path.quadTo(realWidth / 2f, height - 2f * arcHeight, realWidth.toFloat(), realHeight.toFloat())
        path.lineTo(realWidth.toFloat(), 0f)
        path.close()
        return path
    }

    override fun dispatchDraw(canvas: Canvas?) {
        if (showBottomArc && arcHeight > 0) {
            val paint = Paint()
            paint.isAntiAlias = true
            paint.color = Color.WHITE
            val saveCount = canvas?.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null, Canvas.ALL_SAVE_FLAG)
            super.dispatchDraw(canvas)
            paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)
            canvas?.drawPath(clipPath, paint)
            canvas?.restoreToCount(saveCount!!)
            paint.xfermode = null
        } else {
            super.dispatchDraw(canvas)
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        val action = ev?.action
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE) {
            if (canTurn) startTurning(autoTurningTime)
        } else if (action == MotionEvent.ACTION_DOWN) {
            if (canTurn) stopTurning()
        }
        return super.dispatchTouchEvent(ev)
    }

    class CTTurnTask<T>(banner: CTBanner<T>) : Runnable {
        private var reference: WeakReference<CTBanner<T>> = WeakReference<CTBanner<T>>(banner)

        override fun run() {
            val banner = reference.get()
            if (banner != null) {
                if (banner.turning) {
                    val page = banner.loopScrollHelper.getCurrentItem() + 1
                    banner.loopScrollHelper.setCurrentItem(page, true)
                    banner.postDelayed(banner.turnTask, banner.autoTurningTime)
                }
            }
        }
    }
}